package dht.client;

import dht.AbstractTransactionHandler;
import dht.IClientAgent;
import dht.entity.Message;
import dht.entity.MessageType;
import dht.entity.NodeInfo;
import dht.socket.SocketHandler;
import dht.socket.TcpConnection;
import dht.storage.PathUtils;
import dht.throwable.DhtException;

public class ClientTransactionHandlerImpl extends AbstractTransactionHandler {

	protected IClientAgent clientAgent;

	public ClientTransactionHandlerImpl(NodeInfo localInfo,
			NodeInfo remoteInfo, IClientAgent clientAgent,
			TcpConnection tcpConnection) {
		super(localInfo, remoteInfo, tcpConnection);
		this.clientAgent = clientAgent;
	}

	public ClientTransactionHandlerImpl(NodeInfo localInfo,
			SocketHandler socketHandler, IClientAgent clientAgent,
			TcpConnection tcpConnection) {
		super(localInfo, socketHandler, tcpConnection);
		this.clientAgent = clientAgent;
	}

	@Override
	protected void runInitiative(Message msg) {
		switch (msg.getMsgType()) {
		case READ_REQ:
			doReadReq(msg);
			break;
		case WRITE_REQ:
			doWriteReq(msg);
			break;
		case CLIENT_TABLE_REQ:
			doClientTableReq(msg);
			break;
		default:
			break;
		}
	}

	@Override
	protected void runPassive() {
		Message reqMsg = null;
		try {
			reqMsg = socketHandler.readMessage();
		} catch (DhtException e) {
			e.printStackTrace();
			return;
		}
		switch (reqMsg.getMsgType()) {
		default:
			break;
		}
	}

	protected void doReadReq(Message msg) {
		SocketHandler socketHandler = null;
		try {
			socketHandler = tcpConnection
					.genTransactionSocketHandler(remoteInfo);
		} catch (DhtException e) {
			e.printStackTrace();
			return;
		}
		Message respMsg = null;
		do {
			try {
				socketHandler.sendMessage(msg);
				respMsg = socketHandler.readMessage();
				assert (respMsg.getMsgType() == MessageType.READ_RESP || respMsg
						.getMsgType() == MessageType.READ_FWD);
				socketHandler.closeSocket();
			} catch (DhtException e) {
				e.printStackTrace();
				return;
			}
			if (respMsg.getMsgType() == MessageType.READ_RESP) {
				if (respMsg.getDataObject() != null) {
					System.out.print("read success from "
							+ socketHandler.getSocketId());
					System.out.println(" filename: " + respMsg.getFileName()
							+ "/" + respMsg.getDataObject().getBlockName()
							+ " filesize: "
							+ respMsg.getDataObject().getFileSize());
				} else {
					System.out.println("read failed from "
							+ socketHandler.getSocketId()
							+ ", data missing, filename: " + msg.getFileName()
							+ " vnodeId: "
							+ PathUtils.getVnodeId(msg.getFileName()));
				}
				break;
			}
			System.out.print("redirect from " + socketHandler.getSocketId());
			try {
				socketHandler = tcpConnection
						.genTransactionSocketHandler(respMsg.getFwdServerInfo());
			} catch (DhtException e) {
				e.printStackTrace();
			}
			System.out.println(" to " + socketHandler.getSocketId());
		} while (true);
	}

	protected void doWriteReq(Message msg) {
		SocketHandler socketHandler = null;
		try {
			socketHandler = tcpConnection
					.genTransactionSocketHandler(remoteInfo);
		} catch (DhtException e) {
			e.printStackTrace();
			return;
		}
		Message respMsg = null;
		do {
			try {
				socketHandler.sendMessage(msg);
				respMsg = socketHandler.readMessage();
				assert (respMsg.getMsgType() == MessageType.WRITE_RESP || respMsg
						.getMsgType() == MessageType.WRITE_FWD);
				socketHandler.closeSocket();
			} catch (DhtException e) {
				e.printStackTrace();
				return;
			}
			if (respMsg.getMsgType() == MessageType.WRITE_RESP) {
				break;
			}
			try {
				socketHandler = tcpConnection
						.genTransactionSocketHandler(respMsg.getFwdServerInfo());
			} catch (DhtException e) {
				e.printStackTrace();
			}
		} while (true);
	}

	protected void doClientTableReq(Message msg) {
		SocketHandler socketHandler = null;
		try {
			socketHandler = tcpConnection
					.genTransactionSocketHandler(remoteInfo);
		} catch (DhtException e) {
			e.printStackTrace();
			return;
		}
		try {
			socketHandler.sendMessage(msg);
		} catch (DhtException e) {
			e.printStackTrace();
			return;
		}
		Message respMsg = null;
		try {
			respMsg = socketHandler.readMessage();
			assert (respMsg.getMsgType() == MessageType.CLIENT_TABLE_RESP);
		} catch (DhtException e) {
			e.printStackTrace();
			return;
		}
		clientAgent.setRouteTable(respMsg.getClientRouteTable());
		try {
			socketHandler.closeSocket();
		} catch (DhtException e) {
			e.printStackTrace();
			return;
		}
	}

}
